package com.yuanheng100.ems4j.dingtalk;

import com.alibaba.fastjson.JSON;
import com.dingtalk.open.client.api.model.corp.*;
import com.yuanheng100.ems4j.dingtalk.auth.AuthHelper;
import com.yuanheng100.ems4j.dingtalk.config.DingTalkEnv;
import com.yuanheng100.ems4j.dingtalk.department.DepartmentHelper;
import com.yuanheng100.ems4j.dingtalk.exception.OApiException;
import com.yuanheng100.ems4j.dingtalk.media.MediaHelper;
import com.yuanheng100.ems4j.dingtalk.message.ConversationMessageDelivery;
import com.yuanheng100.ems4j.dingtalk.message.LightAppMessageDelivery;
import com.yuanheng100.ems4j.dingtalk.message.MessageHelper;
import com.yuanheng100.ems4j.dingtalk.user.UserHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.List;

/**
 * Created by jlqian on 2017/1/13.
 * 注：被调用的代码来源于：钉钉的DEMO：https://github.com/ddtalk/HarleyCorp
 * 没有使用官方提供的client-sdk.spring-{version}.jar,使用了默认配置
 */
public class DingTalk
{
    private static final Logger logger = LoggerFactory.getLogger(DingTalk.class);

    private DingTalkEnv dDTalkEnv;

    public void setDDTalkEnv(DingTalkEnv dDTalkEnv)
    {
        this.dDTalkEnv = dDTalkEnv;
    }

    /**
     * 创建部门
     *
     * @param name            部门名称。长度限制为1~64个字符
     * @param parentId        父部门id。根部门id为1
     * @param order           在父部门中的次序值。order值小的排序靠前
     * @param createDeptGroup 是否创建一个关联此部门的企业群，默认为false
     * @return
     * @throws OApiException
     */
    public Long createDepartment(String name, String parentId, Integer order, Boolean createDeptGroup)
    {
        Long departmentId = null;
        try
        {
            departmentId = Long.parseLong(DepartmentHelper.createDepartment(AuthHelper.getAccessToken(dDTalkEnv), name, parentId, String.valueOf(order), createDeptGroup));
            logger.info("成功创建部门名称={}，部门id={}", name, departmentId);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return departmentId;
    }

    /**
     * 删除部门
     *
     * @param departmentId 部门id。（注：不能删除根部门；不能删除含有子部门、成员的部门）
     */
    public void deleteDepartment(Long departmentId)
    {
        try
        {
            DepartmentHelper.deleteDepartment(AuthHelper.getAccessToken(dDTalkEnv), departmentId);
            logger.info("成功删除部门, 部门id={}", departmentId);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 更新部门信息
     *
     * @param name                  部门名称。长度限制为1~64个字符
     * @param departmentId          部门id
     * @param parentId              父部门id。根部门id为1
     * @param order                 在父部门中的次序值。order值小的排序靠前
     * @param createDeptGroup       是否创建一个关联此部门的企业群
     * @param autoAddUser           如果有新人加入部门是否会自动加入部门群
     * @param deptManagerUseridList 部门的主管列表,取值为由主管的userid组成的字符串，不同的userid使用’| 符号进行分割
     * @param deptHiding            是否隐藏部门, true表示隐藏, false表示显示
     * @param deptPerimits          可以查看指定隐藏部门的其他部门列表，如果部门隐藏，则此值生效，取值为其他的部门id组成的的字符串，使用 | 符号进行分割
     */
    public void updateDepartment(String name, Long departmentId, Integer parentId, Integer order, Boolean createDeptGroup, Boolean autoAddUser, String deptManagerUseridList, Boolean deptHiding, String deptPerimits)
    {
        try
        {
            DepartmentHelper.updateDepartment(AuthHelper.getAccessToken(dDTalkEnv), departmentId, name, String.valueOf(parentId), String.valueOf(order), createDeptGroup,
                    autoAddUser, deptManagerUseridList, deptHiding, deptPerimits, null, null, null, null, null);
            logger.info("成功更新部门，部门id={}", departmentId);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 获取部门下的所有子部门
     *
     * @param parentDeptId 父部门id
     * @return
     * @throws OApiException
     */
    public List<Department> listDepartments(String parentDeptId)
    {
        List<Department> departments = null;
        try
        {
            departments = DepartmentHelper.listDepartments(AuthHelper.getAccessToken(dDTalkEnv), parentDeptId);
            logger.info("成功获取子部门，子部门部门信息={}", JSON.toJSONString(departments));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return departments;
    }

    /**
     * 获取部门详情
     *
     * @param deptId 部门id
     * @return
     * @throws OApiException
     */
    public DepartmentDetail getDepartmentDetail(String deptId)
    {
        DepartmentDetail departmentDetail = null;
        try
        {
            departmentDetail = DepartmentHelper.getDepartmentDetail(AuthHelper.getAccessToken(dDTalkEnv), deptId);
            logger.info("成功部门详细信息，部门信息={}", JSON.toJSONString(departmentDetail));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return departmentDetail;
    }


    /**
     * 创建成员
     *
     * @param userid      员工唯一标识ID（不可修改），企业内必须唯一。长度为1~64个字符，如果不传，服务器将自动生成一个userid
     * @param name        成员名称。长度为1~64个字符
     * @param email       邮箱。长度为0~64个字符。企业内必须唯一
     * @param mobile      手机号码。企业内必须唯一
     * @param departments 数组类型，数组里面值为整型，成员所属部门id列表
     */
    public void createUser(String userid, String name, String email, String mobile, List<Long> departments)
    {
        CorpUserDetail userDetail = new CorpUserDetail();
        userDetail.setUserid(userid);
        userDetail.setName(name);
        userDetail.setEmail(email);
        userDetail.setMobile(mobile);
        userDetail.setDepartment(departments);

        try
        {
            UserHelper.createUser(AuthHelper.getAccessToken(dDTalkEnv), userDetail);
            logger.info("成功创建成员，成员信息={}", JSON.toJSONString(userDetail));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 删除成员
     *
     * @param userid 员工唯一标识ID（不可修改）
     */
    public void deleteUser(String userid)
    {
        try
        {
            UserHelper.deleteUser(AuthHelper.getAccessToken(dDTalkEnv), userid);
            logger.info("成功删除成员, 成员userid={}", userid);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 批量删除成员
     *
     * @param useridlist 员工UserID列表。列表长度在1到20之间
     */
    public void batchDeleteUser(List<String> useridlist)
    {
        try
        {
            UserHelper.batchDeleteUser(AuthHelper.getAccessToken(dDTalkEnv), useridlist);
            logger.info("成功批量删除成员, 成员列表useridlist={}", JSON.toJSONString(useridlist));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 修改成员信息
     *
     * @param userid     员工唯一标识ID（不可修改），企业内必须唯一。长度为1~64个字符
     * @param name       成员名称。长度为1~64个字符
     * @param department 成员所属部门id列表
     * @param email      邮箱。长度为0~64个字符。企业内必须唯一
     * @param mobile     手机号码。企业内必须唯一
     */
    public void updateUser(String userid, String name, List<Long> department, String email, String mobile)
    {
        CorpUserDetail userDetail = new CorpUserDetail();
        userDetail.setUserid(userid);
        userDetail.setName(name);
        userDetail.setEmail(email);
        userDetail.setMobile(mobile);
        userDetail.setDepartment(department);

        try
        {
            UserHelper.updateUser(AuthHelper.getAccessToken(dDTalkEnv), userDetail);
            logger.info("成功更新成员，成员信息={}", userDetail);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }

    /**
     * 获取成员
     *
     * @param userid 员工在企业内的UserID，企业用来唯一标识用户的字段。
     * @return
     */
    public CorpUserDetail getUser(String userid)
    {
        CorpUserDetail userDetail = null;
        try
        {
            userDetail = UserHelper.getUser(AuthHelper.getAccessToken(dDTalkEnv), userid);
            logger.info("成功获取成员, 成员信息={}", userDetail);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return userDetail;
    }

    /**
     * 获取部门成员
     *
     * @param departmentId 获取的部门id
     * @param offset       支持分页查询，与size参数同时设置时才生效，此参数代表偏移量
     * @param size         支持分页查询，与offset参数同时设置时才生效，此参数代表分页大小，最大100
     * @param order        支持分页查询，部门成员的排序规则，默认不传是按自定义排序；entry_asc代表按照进入部门的时间升序，entry_desc代表按照进入部门的时间降序，modify_asc代表按照部门信息修改时间升序，modify_desc代表按照部门信息修改时间降序，custom代表用户定义(未定义时按照拼音)排序
     * @return
     */
    public CorpUserList getDepartmentUser(Long departmentId, Long offset, Integer size, Integer order)
    {
        CorpUserList userList = null;
        try
        {
            userList = UserHelper.getDepartmentUser(AuthHelper.getAccessToken(dDTalkEnv), departmentId, offset, size, String.valueOf(order));
            logger.info("成功获取部门成员, 部门成员信息={}", JSON.toJSONString(userList.getUserlist()));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return userList;
    }

    /**
     * 获取部门成员的详细信息
     *
     * @param departmentId 获取的部门id
     * @param offset       支持分页查询，与size参数同时设置时才生效，此参数代表偏移量
     * @param size         支持分页查询，与offset参数同时设置时才生效，此参数代表分页大小，最大100
     * @param order        支持分页查询，部门成员的排序规则，默认不传是按自定义排序；entry_asc代表按照进入部门的时间升序，entry_desc代表按照进入部门的时间降序，modify_asc代表按照部门信息修改时间升序，modify_desc代表按照部门信息修改时间降序，custom代表用户定义(未定义时按照拼音)排序
     * @return
     */
    public CorpUserDetailList getDepartmentUserDetails(Long departmentId, Long offset, Integer size, Integer order)
    {
        CorpUserDetailList userList = null;
        try
        {
            userList = UserHelper.getUserDetails(AuthHelper.getAccessToken(dDTalkEnv), departmentId, offset, size, String.valueOf(order));
            logger.info("成功获取部门成员详情, 部门成员详情信息={}", JSON.toJSONString(userList.getUserlist()));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return userList;
    }

    /**
     * 上传媒体文件
     *
     * @param type 媒体文件类型，分别有图片（image）、语音（voice）、普通文件(file)
     * @param file 上传的文件
     * @return
     */
    public UploadResult uploadMedia(MediaHelper.Type type, File file)
    {
        UploadResult uploadResult = null;
        try
        {
            uploadResult = MediaHelper.upload(AuthHelper.getAccessToken(dDTalkEnv), MediaHelper.Type.IMAGE, file);
            logger.info("上传文件{}结果为{}", type.name(), JSON.toJSONString(uploadResult));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return uploadResult;
    }

    /**
     * 获取媒体文件
     *
     * @param media_id 媒体文件的唯一标示
     * @param fileDir  文件下载到本地的位置
     */
    public void downloadMedia(String media_id, String fileDir)
    {
        try
        {
            MediaHelper.download(AuthHelper.getAccessToken(dDTalkEnv), media_id, fileDir);
            logger.info("下载媒体文件成功, 媒体唯一标识为：{}", media_id);
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
    }


    public String sendConversationMessage(String sender, String cid, MessageBody messageBody)
    {
        String result = null;
        ConversationMessageDelivery conversationMessageDelivery = new ConversationMessageDelivery(sender, cid, null);
        try
        {
            String accessToken = AuthHelper.getAccessToken(dDTalkEnv);
            if (messageBody instanceof MessageBody.TextBody)
            {
                conversationMessageDelivery.withMessage(MessageType.TEXT, messageBody);
            } else if (messageBody instanceof MessageBody.ImageBody)
            {
                conversationMessageDelivery.withMessage(MessageType.IMAGE, messageBody);
            } else if (messageBody instanceof MessageBody.LinkBody)
            {
                conversationMessageDelivery.withMessage(MessageType.LINK, messageBody);
            } else if (messageBody instanceof MessageBody.VoiceBody)
            {
                conversationMessageDelivery.withMessage(MessageType.VOICE, messageBody);
            } else if (messageBody instanceof MessageBody.FileBody)
            {
                conversationMessageDelivery.withMessage(MessageType.FILE, messageBody);
            } else if (messageBody instanceof MessageBody.OABody)
            {
                conversationMessageDelivery.withMessage(MessageType.OA, messageBody);
            } else
            {
                throw new OApiException(404, "消息类型不存在");
            }
            result = MessageHelper.send(accessToken, conversationMessageDelivery);
            logger.debug("成功发送会话消息");
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return result;
    }

    /**
     * 发送企业会话消息
     *
     * @param toUsers   员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties 部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId   企业应用id，这个值代表以哪个应用的名义发送消息
     */
    public MessageHelper.Receipt sendMessage(String toUsers, String toParties, String agentId, MessageBody messageBody)
    {
        MessageHelper.Receipt receipt = null;
        LightAppMessageDelivery lightAppMessageDelivery = new LightAppMessageDelivery(toUsers, toParties, agentId);
        try
        {
            String accessToken = AuthHelper.getAccessToken(dDTalkEnv);
            if (messageBody instanceof MessageBody.TextBody)
            {
                lightAppMessageDelivery.withMessage(MessageType.TEXT, messageBody);

            } else if (messageBody instanceof MessageBody.ImageBody)
            {
                lightAppMessageDelivery.withMessage(MessageType.IMAGE, messageBody);
            } else if (messageBody instanceof MessageBody.LinkBody)
            {
                lightAppMessageDelivery.withMessage(MessageType.LINK, messageBody);
            } else if (messageBody instanceof MessageBody.VoiceBody)
            {
                lightAppMessageDelivery.withMessage(MessageType.VOICE, messageBody);
            } else if (messageBody instanceof MessageBody.FileBody)
            {
                lightAppMessageDelivery.withMessage(MessageType.FILE, messageBody);
            } else if (messageBody instanceof MessageBody.OABody)
            {
                lightAppMessageDelivery.withMessage(MessageType.OA, messageBody);
            } else
            {
                throw new OApiException(404, "消息类型不存在");
            }
            receipt = MessageHelper.send(accessToken, lightAppMessageDelivery);
            logger.info("成功发送微应用消息{}", JSON.toJSONString(lightAppMessageDelivery));
        } catch (Exception e)
        {
            logger.error(e.getMessage(), e);
        }
        return receipt;
    }

    /**
     * 发送企业会话消息【文本】
     *
     * @param toUsers   员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties 部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId   企业应用id，这个值代表以哪个应用的名义发送消息
     * @param content   消息内容
     * @return
     */
    public MessageHelper.Receipt sendTextMessage(String toUsers, String toParties, String agentId, String content)
    {
        MessageBody.TextBody textBody = new MessageBody.TextBody();
        textBody.setContent(content);
        return sendMessage(toUsers, toParties, agentId, textBody);
    }

    /**
     * 发送企业会话消息【图片】
     *
     * @param toUsers   员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties 部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId   企业应用id，这个值代表以哪个应用的名义发送消息
     * @param media_id  图片媒体文件id，可以调用上传媒体文件接口获取。建议宽600像素 x 400像素，宽高比3：2
     * @return
     */
    public MessageHelper.Receipt sendImageMessage(String toUsers, String toParties, String agentId, String media_id)
    {
        MessageBody.ImageBody imageBody = new MessageBody.ImageBody();
        imageBody.setMedia_id(media_id);
        return sendMessage(toUsers, toParties, agentId, imageBody);
    }

    /**
     * 发送企业会话消息【语音】
     *
     * @param toUsers   员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties 部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId   企业应用id，这个值代表以哪个应用的名义发送消息
     * @param media_id  语音媒体文件id，可以调用上传媒体文件接口获取。2MB，播放长度不超过60s，AMR格式
     * @return
     */
    public MessageHelper.Receipt sendVoiceMessage(String toUsers, String toParties, String agentId, String media_id)
    {
        MessageBody.VoiceBody voiceBody = new MessageBody.VoiceBody();
        voiceBody.setMedia_id(media_id);
        return sendMessage(toUsers, toParties, agentId, voiceBody);
    }

    /**
     * 发送企业会话消息【文件】
     *
     * @param toUsers   员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties 部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId   企业应用id，这个值代表以哪个应用的名义发送消息
     * @param media_id  媒体文件id，可以调用上传媒体文件接口获取。10MB
     * @return
     */
    public MessageHelper.Receipt sendFileMessage(String toUsers, String toParties, String agentId, String media_id)
    {
        MessageBody.FileBody fileBody = new MessageBody.FileBody();
        fileBody.setMedia_id(media_id);
        return sendMessage(toUsers, toParties, agentId, fileBody);
    }

    /**
     * 发送企业会话消息【link】
     *
     * @param toUsers    员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties  部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId    企业应用id，这个值代表以哪个应用的名义发送消息
     * @param messageUrl 消息点击链接地址
     * @param picUrl     图片媒体文件id，可以调用上传媒体文件接口获取
     * @param title      消息标题
     * @param text       消息描述
     * @return
     */
    public MessageHelper.Receipt sendLinkMessage(String toUsers, String toParties, String agentId, String messageUrl, String picUrl, String title, String text)
    {
        MessageBody.LinkBody linkBody = new MessageBody.LinkBody();
        linkBody.setMessageUrl(messageUrl);
        linkBody.setPicUrl(picUrl);
        linkBody.setTitle(title);
        linkBody.setText(text);
        return sendMessage(toUsers, toParties, agentId, linkBody);
    }

    /**
     * 发送企业会话消息【OA】
     *
     * @param toUsers      员工id列表（消息接收者，多个接收者用|分隔）
     * @param toParties    部门id列表，多个接收者用|分隔。touser或者toparty 二者有一个必填
     * @param agentId      企业应用id，这个值代表以哪个应用的名义发送消息
     * @param message_url  客户端点击消息时跳转到的H5地址
     * @param head_bgcolor 消息头部的背景颜色。长度限制为8个英文字符，其中前2为表示透明度，后6位表示颜色值。不要添加0x
     * @param head_text    消息的头部标题（仅适用于发送普通场景）
     * @param body         消息体
     * @return
     */
    public MessageHelper.Receipt sendLinkMessage(String toUsers, String toParties, String agentId,
                                                 String message_url, String head_text, String head_bgcolor,
                                                 MessageBody.OABody.Body body)
    {
        MessageBody.OABody oaBody = new MessageBody.OABody();
        oaBody.setMessage_url(message_url);

        MessageBody.OABody.Head head = new MessageBody.OABody.Head();
        head.setText(head_text);
        head.setBgcolor(head_bgcolor);
        oaBody.setHead(head);

        oaBody.setBody(body);
        return sendMessage(toUsers, toParties, agentId, oaBody);
    }
}
